﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MKDataBase.Contracts;
using System.Xml.Linq;
using System.Drawing;
using System.IO;

namespace MKDataBase.Implementation
{
    public class XMLDBProvider : IDBProvider
    {
        #region Constructor and Properties
        string XmlManagerString = Directory.GetCurrentDirectory() + @"\XMLDBFiles\MKMovieManager.xml";
        string XmlMovieDetails = Directory.GetCurrentDirectory() + @"\XMLDBFiles\MovieDetails.xml";
        IDBProvider idbprovider;
        /// <summary>
        /// 
        /// </summary>
        XDocument movieManager;
        /// <summary>
        /// 
        /// </summary>
        XDocument movieDetails;
        /// <summary>
        /// Initializes a new instance of the <see cref="XMLDBProvider"/> class.
        /// </summary>
        public XMLDBProvider()
        {            
            movieManager = XDocument.Load(XmlManagerString);
            movieDetails = XDocument.Load(XmlMovieDetails);
        }
        #endregion
        #region MovieManager

        /// <summary>
        /// Adds the A movie.
        /// </summary>
        /// <param name="row">The row.</param>
        /// <returns></returns>
        public Contracts.DBStatus AddAMovie(MovieManagerDataRow row)
        {
            try
            {
                var movieXml = row.MapToXml();
                //verify if movie already exists
                bool MovieExists = movieManager.Element("MovieManager").Elements("Movie").Where(m => row.MovieName == MapFrom(m).MovieName).Any();
                if (MovieExists)
                    return DBStatus.RowExists;

                //Find Movie id
                var movies = movieManager.Element("MovieManager").Elements("Movie");
                var id = movies.Any() ? movies.Select(m => MapFrom(m).MovieID).Max() + 1 : 0;
                movieXml.Add(new XAttribute("Id", id));
                movieManager.Element("MovieManager").Add(movieXml);
            }
            catch
            {
                return DBStatus.Exception;
            }
            movieManager.Save(XmlManagerString);
            return DBStatus.Success;
        }

        /// <summary>
        /// Gets the movies.
        /// </summary>
        /// <returns></returns>
        public List<MovieManagerDataRow> GetMovies()
        {
            return movieManager.Element("MovieManager").Elements("Movie").Select(m => MapFrom(m)).OrderBy(mr => mr.MovieName).ToList();
        }

        /// <summary>
        /// Ups the date movie.
        /// </summary>
        /// <param name="row">The row.</param>
        /// <returns></returns>
        public DBStatus UpDateMovie(MovieManagerDataRow row)
        {
            try
            {
                var movieXml = row.MapToXml();
                //verify if movie already exists
                XElement MovieExists = movieManager.Element("MovieManager").Elements("Movie").Where(m => row.MovieID == MapFrom(m).MovieID).First();
                if (MovieExists != null)
                    MovieExists.SetElementValue("MovieName", row.MovieName);
                else
                    return DBStatus.RowDoesNotExist;                
            }
            catch
            {
                return DBStatus.Exception;
            }
            movieManager.Save(XmlManagerString);
            return DBStatus.Success;
        }
        /// <summary>
        /// Maps from.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        public MovieManagerDataRow MapFrom(XElement element)
        {
            var movieName = element.Element("MovieName").Value;
            var moviePath = element.Element("MoviePath").Value;
            var language = element.Element("Language").Value;
            var id = Convert.ToInt32(element.Attribute("Id").Value);
            return new MovieManagerDataRow()
            {
                MovieName = movieName,
                MoviePath = moviePath,
                Language = language,
                MovieID = id
            };
        }
        #endregion

        #region MovieDetails
        /// <summary>
        /// Adds the movie details.
        /// </summary>
        /// <param name="row">The row.</param>
        /// <returns></returns>
        public Contracts.DBStatus AddMovieDetails(MovieDetailsDataRow row)
        {
            try
            {
                var movieXml = row.MapToXml();
                //verify if the movie details exists
                var movieExists = (from m in movieDetails.Element("MovieDetails").Elements("Movie")
                                   let x = MapToMovieDetails(m)
                                   where x.ID == row.ID && x.IMDBId == row.IMDBId
                                   select m).Any();
                if (!movieExists)
                    movieDetails.Element("MovieDetails").Add(movieXml);
                else
                    return DBStatus.RowExists;
            }
            catch
            {
                return DBStatus.Exception;
            }
            movieDetails.Save(XmlMovieDetails);
            return DBStatus.Success;
        }

        /// <summary>
        /// Gets the movie details by id.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        public MovieDetailsDataRow GetMovieDetailsById(int id)
        {
            var movieDetail = from m in movieDetails.Element("MovieDetails").Elements("Movie")
                              let x = MapToMovieDetails(m)
                              where x != null && x.ID == id
                              select x;

            return movieDetail.Any() ? movieDetail.First() : null;
        }

        /// <summary>
        /// Maps to movie details.
        /// </summary>
        /// <param name="obj">The obj.</param>
        /// <returns></returns>
        public MovieDetailsDataRow MapToMovieDetails(object obj)
        {
            XElement movie = obj as XElement;
            if (movie == null)
                return null;
            MovieDetailsDataRow movieRow = new MovieDetailsDataRow();
            movieRow.ID = Convert.ToInt32(movie.Attribute("Id").Value);
            movieRow.Title = movie.Element("Title").Value;
            movieRow.IMDBId = movie.Element("IMDBId").Value;
            movieRow.IMDBUrl = movie.Element("IMDBUrl").Value;
            movieRow.TagLine = movie.Element("TagLine").Value;
            movieRow.StoryLine = movie.Element("StoryLine").Value;
            var Imagepath = movie.Element("ImagePath").Value;
            byte[] imgAry;
            try
            {
                FileStream imgFile = new FileStream(Imagepath, FileMode.Open);
                imgAry = new byte[imgFile.Length];
                imgFile.Read(imgAry, 0, imgAry.Length);
                imgFile.Close();
            }
            catch
            {
                imgAry = new byte[0];
            }
            movieRow.MovieImage = imgAry;
            movieRow.Genre = movie.Element("Genre").Value;
            movieRow.Releasedate = Convert.ToDateTime(movie.Element("ReleaseDate").Value);
            movieRow.Rating = Convert.ToSingle(movie.Element("Rating").Value);
            return movieRow;
        }
        #endregion


        public bool DeleteMovie(string MovieName, int id)
        {
            try
            {
                //Delete From Movie Details
                var movieDetail = from m in movieDetails.Element("MovieDetails").Elements("Movie")
                                  let x = MapToMovieDetails(m)
                                  where x != null && x.ID == id
                                  select m;
                if (movieDetail.Any())
                {
                    movieDetail.First().Remove();
                    movieDetails.Save(XmlMovieDetails);
                }
                //Delete From MovieManager

                var movie = from m in movieManager.Element("MovieManager").Elements("Movie")
                            let x = MapFrom(m)
                            where x != null && x.MovieName == MovieName && x.MovieID == id
                            select m;
                if (movie.Any())
                {
                    movie.First().Remove();
                    movieManager.Save(XmlManagerString);
                }
            }
            catch
            {
                return false;
            }
            return true;
        }

        public DBStatus UpdateMovieDetails(MovieDetailsDataRow row)
        {
            try
            {
                var movieXml = row.MapToXml();
                //verify if movie already exists
                XElement MovieExists = movieManager.Element("MovieManager").Elements("Movie").Where(m => row.ID == MapFrom(m).MovieID).First();
                if (MovieExists != null)
                    MovieExists.SetElementValue("MovieName", row.Title);
                else
                    return DBStatus.RowDoesNotExist;
            }
            catch
            {
                return DBStatus.Exception;
            }
            movieManager.Save(XmlManagerString);
            return DBStatus.Success;
        }

        public IDBProvider CurrentDB
        {
            get
            {
                if (idbprovider == null)
                    idbprovider = new XMLDBProvider();
                return idbprovider;
            }
        }
        private static IDBProvider idb;
        public static IDBProvider GetInstance
        {
            get
            {
                if (idb == null)
                    idb = new XMLDBProvider();
                return idb;
            }
        }
    }
}
